spring boot-mybatis开发速成指南

2022-12-01 22:26:10

技术

Spring Boot makes it easy to create stand-alone, production-grade Spring based Applications that you can "just run". We take an opinionated view of the Spring platform and third-party libraries so you can get started with minimum fuss. Most Spring Boot applications need minimal Spring configuration.

本文的目的:了解一个spring boot项目结构的关系,知道我们应该在哪个部分做什么事

参考项目结构

|_java.com.cy.store
    |_aop
    |_config
    |_controller
    |_entity
    |_interceptor
    |_mapper
    |_service
        |_ex
        |_impl
    |_util
    |_vo

    XXXApplication

|_resource
    |_mapper
    |_static
    |_templates

    application.yml/application.properties

不同项目项目结构不一样,但一般来讲,理清controller控制层、service业务逻辑层、mapper(dao)数据访问层三层关系即可

推荐项目学习
该视频下方有热心小伙伴的文档笔记整理 个人认为只看一个功能即可,其他大同小异,我只了解完用户注册剩下的大概看看就行了,主要是了解一个spring boot项目的整体思路

三层关系

controller、service、mapper三层关系梳理1

controller、service、mapper三层关系梳理2

数据库(表)设计

快速学习数据库设计步骤

实体层(编写实体类)

entity(或叫model)实体,该层存放实体类,属性值与数据库中的属性值保持一致,实现set和get方法,可使用@Data注解自动生成

多个类拥有同一些属性,可以把这些属性抽取成一个公共基类这样方便我们管理。例如数据库许多实体类都需要有日志相关的四个属性:创建者和时间以及修改者和时间,则可先创建包含这些属性的基类,然后其他实体类再继承这个基类

持久层 (java对象与sql映射)(Mapper接口与xml映射文件绑定)

sql与xml绑定

mapper(或叫dao),为映射的意思;
dao(data access object),数据访问对象

持久层的意思是使数据可以永久保持地存储,可以直接理解为对数据库的CRUD等操作,就是把持久的动作封装成一个独立的层。这是为了降低功能代码之间的关联,创建一个更清晰的抽象,提高代码的内聚力,降低代码的耦合度,提高可维护性和复用性.

Mybatis 对jdbc 的操作数据库的过程进行封装,通过xml或注解的方式将要执行的各种statement(statement、preparedStatemnt)配置起来,并通过java对象和statement中的sql进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射成java对象并返回。

总之:

  1. 确定好需要写的sql;
  2. 在java文件夹下的mapper包编写持久层接口(Mapper接口):XxxxMapper,在接口中定义需要实现的抽象方法;
  3. 在resource文件夹下的mapper包编写xml映射文件:XxxxMapper.xml,编写对应Mapper接口的方法的sql(抽象方法的映射配置),接口与xml文件绑定

1)Mapper 接口与 XML 文件的绑定是通过 XML 里 mapper 标签的 namespace 值与 Mapper 接口的 包路径.接口名 进行绑定

2) Mapper 接口的方法名与 XML 文件中的 sql、select、insert、update、delete 标签的 id 参数值进行绑定

在配置文件中说明xml配置:mybatis.mapper-locations=classpath:mapper/*.xml

业务逻辑层

DAO层和Service层的理解

service 服务,此处翻译为业务比较合适,service层处理业务逻辑 mapper层是对数据库的操作,不涉及业务逻辑,具体是对某张表的增删查改

service是业务逻辑,一个业务(功能)对应多项操作,需要有数据的处理流程和逻辑

流程:先做什么,再做什么
逻辑:能做什么,不能做什么

例:用户注册

mapper层:UserMapper中定义insert()方法(插入用户数据)、findByUsername()方法(根据用户名查询数据)

service层:UserService中定义的一个业务逻辑(功能)为reg()(用户注册),reg()在数据库层面的理解其实就是insert(),但是insert()不涉及数据处理流程和逻辑

reg()的业务逻辑:先根据输入的用户名查询是否已存在用户数据(调用UserMapperfindByUsername()),如果不存在则插入用户数据(调用用UserMapperinsert()),如果存在则抛出用户已存在的异常。

在service包中,先在IUserService接口中定义reg()的抽象方法,然后在service.impl(implement:实现)包中的UserServiceImpl实现类中实现reg()方法


总之:

  1. 规划可能出现的异常,如用户名重复等,写在Service.ex包下
  2. 直接在在Service包下编写业务层接口(service接口):IXxxxService,该命名方式开头的I表示接口,接口中定义要实现的抽象方法——业务逻辑(功能)
  3. 在service.impl包下编写service接口的实现类:XxxxServiceImpl,实现相应service接口中的抽象方法

控制层

controller的注解1
controller的注解2
controller请求与响应
controller请求与响应生动讲解
controller请求与响应生动讲解(续)

Controller 控制器,与前端和service层交互, 把用户提交来的请求通过对URL的匹配,分配不同的接收器,再进行处理,然后向用户返回结果。

从HTTP请求中获取信息,提取参数,并将其分发给不同的处理服务(service层),根据实际需求调用不同的service定义的方法来处理不同业务,并向前端返回service层处理后的数据,他的重点就在于如何从HTTP请求中获得信息,提取参数,并分发给不同的处理服务。接收和响应请求,校验数据

controller负责管理service,service负责实施


例:用户注册

@RestController
@RequestMapping("users")
public class UserController extends BaseController {
    @Autowired
    private IUserService userService;


    @RequestMapping("reg")
    public JsonResult<Void> reg(User user) {
        // 调用业务对象执行注册
        userService.reg(user);
        // 返回
        return new JsonResult<Void>(200);
    }
//省略其他代码
 }

在UserController中实例化IUserService对象userService;

@RequestMapping("users")@RequestMapping("reg")请求映射,将http请求路径映射到Controller方法上;

当用户在前端点击注册后,前端请求通过.../users/reg的路径发送给后端的UserController,执行@RequestMapping("reg")下的reg()方法;

注意这里的reg()是Controller层的,不负责“用户注册”这个业务的实现,它会调用Service层真正实现“用户注册”业务逻辑的userService.reg();

然后userService.reg()调用mapper层的数据库操作方法findByUsername()insert(),根据映射的xml文件通过Mybatis执行sql连接操作数据库,把数据写入数据库,完成该业务逻辑,但还需要返回响应结果

.../users请求路径是映射到@RequestMapping("users")下面的UserController类; .../users/reg请求路径映射到@RequestMapping("users")之下的@RequestMapping("reg")下面的reg方法


再看一下上面的
return new JsonResult<Void>(200);

JsonResult是自定义的响应结果类,统一返回结果 上面的200表示正常,即注册成功,如果成功执行了reg方法,则会创建一个JsonResult类的对象,其中state(状态码)属性值设置为200

自定义的JsonResult类包含属性state(状态码)、message(状态描述信息)、data(数据),这里注册只需要知道是否操作成功就只返回状态码,如查询等业务则会还需要返回数据等

下面看一下前端代码,这个例子的前端用的是Thymeleaf模板引擎

<script type="text/javascript">
    $("#btn-reg").click(function() {
        $.ajax({
            url: "/users/reg",
            type: "POST",
            data: $("#form-reg").serialize(),
            dataType: "json",
            success: function(json) {
                if (json.state == 200) {
                    alert("注册成功!");
                    // location.href = "login.html";
                } else {
                    alert("注册失败!" + json.message);
                }
            }
        });
    });
</script>

第四行的url即为上面提到前端的请求路径,该请求为post请求、提交数据,数据来源于id等于第六行"#form-reg"的表单(form),内容为用户注册所需要的信息,与User类属性一致,然后转化为json对象传给Controller,该对象(实参)在Controller中为User类的对象user(形参)

public JsonResult<Void> reg(User user)

后端的Controller接收该请求,当处理完请求后返回结果给前端 如上success: function(json)表示请求成功并返回信息(响应请求),这里括号里的json就是后端Controller返回的结果,即一个JsonResult类的对象(实参),其state属性值为200,在前端中这个对象被命名为json(形参),那么Controller返回结果成功则json.state==200.

以上即为前后端交互的流程,Controller负责接收请求和响应请求,调用Service处理业务,但自身不涉及业务逻辑

总之:

  1. 考虑要实现一个业务逻辑,用户在前端界面操作,该操作会从前端向后端传递什么,后端处理完该业务逻辑需要返回给前端什么
  2. 设计请求与响应,例: 请求路径:/users/reg 请求参数:User user 请求类型:POST 响应结果:JsonResult
  3. 在Controller包下编写控制器类:XxxxController,在类中实例化需要调用的service对象:xxxxService
  4. XxxxController中编写要实现业务的控制方法,包括请求参数与响应结果(返回值),调用xxxxService对象的xxx()方法
  5. 使用@RequestMapping等注解映射控制方法的请求路径,实现前后端的交互

总结

用户操作前端界面,需要实现某种业务--前端发送请求给后端controller--controller接收请求,调用service处理该业务 --service处理业务调用mapper的数据库操作方法 --mapper方法与mapper.xml存在映射关系;--Mybatis执行sql--service处理业完毕--controller返回响应结果--前端返回反馈给用户

用户操作前端界面,需要实现某种业务(<?> 操作内容){
    //前端api接口
    <操作反馈> 前端发送请求给后端controller (){
        <?> 请求路径
        <?> 请求参数
        <?> 请求类型
        <?> 响应结果
        //controller层
        <响应结果> controller接收请求,调用service处理该业务 (<?> 请求参数){
            //service层
            service处理业务时,调用mapper的数据库操作方法 (<?> 请求参数){
                //mapper层
                mapper方法与mapper.xml存在映射关系;
                //resource文件夹下的mapper的xml文件
                执行sql;
            }
        }
    } 
}

考虑的时候可以是前端---controller---service---dao---database ; 写代码的时候则database---dao---service---controller---前端

总而言之,言而总之

在mapper层

  1. 确定好需要写的sql;
  2. 在java文件夹下的mapper包编写持久层接口(Mapper接口):XxxxMapper,在接口中定义需要实现的抽象方法;
  3. 在resource文件夹下的mapper包编写xml映射文件:XxxxMapper.xml,编写对应Mapper接口的方法的sql(抽象方法的映射配置),接口与xml文件绑定

在service层

  1. 规划可能出现的异常,如用户名重复等,写在Service.ex包下
  2. 直接在在Service包下编写业务层接口(service接口):IXxxxService,该命名方式开头的I表示接口,接口中定义要实现的抽象方法——业务逻辑(功能)
  3. 在service.impl包下编写service接口的实现类:XxxxServiceImpl,实现相应service接口中的抽象方法

在controller层

  1. 考虑要实现一个业务逻辑,用户在前端界面操作,该操作会从前端向后端传递什么,后端处理完该业务逻辑需要返回给前端什么
  2. 设计请求与响应,例: 请求路径:/users/reg 请求参数:User user 请求类型:POST 响应结果:JsonResult
  3. 在Controller包下编写控制器类:XxxxController,在类中实例化需要调用的service对象:xxxxService
  4. XxxxController中编写要实现业务的控制方法,包括请求参数与响应结果(返回值),调用xxxxService对象的xxx()方法
  5. 使用@RequestMapping等注解映射控制方法的请求路径,实现前后端的交互